package com.snap.vseries.analyze;

public class SmoothUtil {

    /**
     * 3点线性平滑
     */
    public static float[] linearSmooth3(float[] in) {
        int length = in.length;
        float[] out = new float[length];
        if (length < 3) {
            System.arraycopy(in, 0, out, 0, length);
        } else {
            out[0] = (5 * in[0] + 2 * in[1] - in[2]) / 6f;
            for (int i = 1; i <= length - 2; i++) {
                out[i] = (in[i - 1] + in[i] + in[i + 1]) / 3f;
            }
            out[length - 1] = (5 * in[length - 1] + 2 * in[length - 2] - in[length - 3]) / 6f;
        }
        return out;
    }

    /**
     * 5点线性平滑
     */
    public static float[] linearSmooth5(float[] in) {
        int length = in.length;
        float[] out = new float[length];
        if (length < 5) {
            System.arraycopy(in, 0, out, 0, length);
        } else {
            out[0] = (3 * in[0] + 2 * in[1] + in[2] - in[4]) / 5f;
            out[1] = (4 * in[0] + 3 * in[1] + 2 * in[2] + in[3]) / 10f;
            for (int i = 2; i <= length - 3; i++) {
                out[i] = (in[i - 2] + in[i - 1] + in[i] + in[i + 1] + in[i + 2]) / 5f;
            }
            out[length - 2] = (4 * in[length - 1] + 3 * in[length - 2] + 2 * in[length - 3] + in[length - 4]) / 10f;
            out[length - 1] = (3 * in[length - 1] + 2 * in[length - 2] + in[length - 3] - in[length - 5]) / 5f;
        }
        return out;
    }

    /**
     * 7点线性平滑
     */
    public static float[] linearSmooth7(float[] in) {
        int length = in.length;
        float[] out = new float[length];
        if (length < 7) {
            System.arraycopy(in, 0, out, 0, length);
        } else {
            out[0] = (13 * in[0] + 10 * in[1] + 7 * in[2] + 4 * in[3] + in[4] - 2 * in[5] - 5 * in[6]) / 28f;
            out[1] = (5 * in[0] + 4 * in[1] + 3 * in[2] + 2 * in[3] + in[4] - in[6]) / 14f;
            out[2] = (7 * in[0] + 6 * in[1] + 5 * in[2] + 4 * in[3] + 3 * in[4] + 2 * in[5] + in[6]) / 28f;
            for (int i = 3; i <= length - 4; i++) {
                out[i] = (in[i - 3] + in[i - 2] + in[i - 1] + in[i] + in[i + 1] + in[i + 2] + in[i + 3]) / 7f;
            }
            out[length - 3] = (7 * in[length - 1] + 6 * in[length - 2] + 5 * in[length - 3] + 4 * in[length - 4] + 3 * in[length - 5] + 2 * in[length - 6] + in[length - 7]) / 28f;
            out[length - 2] = (5 * in[length - 1] + 4 * in[length - 2] + 3 * in[length - 3] + 2 * in[length - 4] + in[length - 5] - in[length - 7]) / 14f;
            out[length - 1] = (13 * in[length - 1] + 10 * in[length - 2] + 7 * in[length - 3] + 4 * in[length - 4] + in[length - 5] - 2 * in[length - 6] - 5 * in[length - 7]) / 28f;
        }
        return out;
    }

    /**
     * 5点二次函数平滑
     */
    public static float[] quadraticSmooth5(float[] in) {
        int length = in.length;
        float[] out = new float[length];
        if (length < 5) {
            System.arraycopy(in, 0, out, 0, length);
        } else {
            out[0] = (31 * in[0] + 9 * in[1] - 3 * in[2] - 5 * in[3] + 3 * in[4]) / 35f;
            out[1] = (9 * in[0] + 13 * in[1] + 12 * in[2] + 6 * in[3] - 5 * in[4]) / 35f;
            for (int i = 2; i <= length - 3; i++) {
                out[i] = (-3 * (in[i - 2] + in[i + 2]) + 12 * (in[i - 1] + in[i + 1]) + 17 * in[i]) / 35f;
            }
            out[length - 2] = (9 * in[length - 1] + 13 * in[length - 2] + 12 * in[length - 3] + 6 * in[length - 4] - 5 * in[length - 5]) / 35f;
            out[length - 1] = (31 * in[length - 1] + 9 * in[length - 2] - 3 * in[length - 3] - 5 * in[length - 4] + 3 * in[length - 5]) / 35f;
        }
        return out;
    }

    /**
     * 7点二次函数平滑
     */
    public static float[] quadraticSmooth7(float[] in) {
        int length = in.length;
        float[] out = new float[length];
        if (length < 7) {
            System.arraycopy(in, 0, out, 0, length);
        } else {
            out[0] = (32 * in[0] + 15 * in[1] + 3 * in[2] - 4 * in[3] - 6 * in[4] - 3 * in[5] + 5 * in[6]) / 42f;
            out[1] = (5 * in[0] + 4 * in[1] + 3 * in[2] + 2 * in[3] + in[4] - in[6]) / 14f;
            out[2] = (1 * in[0] + 3 * in[1] + 4 * in[2] + 4 * in[3] + 3 * in[4] + 1 * in[5] - 2 * in[6]) / 14f;
            for (int i = 3; i <= length - 4; i++) {
                out[i] = (-2 * (in[i - 3] + in[i + 3]) + 3 * (in[i - 2] + in[i + 2]) + 6 * (in[i - 1] + in[i + 1]) + 7 * in[i]) / 21f;
            }
            out[length - 3] = (1 * in[length - 1] + 3 * in[length - 2] + 4 * in[length - 3] + 4 * in[length - 4] + 3 * in[length - 5] + 1 * in[length - 6] - 2 * in[length - 7]) / 14f;
            out[length - 2] = (5 * in[length - 1] + 4 * in[length - 2] + 3 * in[length - 3] + 2 * in[length - 4] + in[length - 5] - in[length - 7]) / 14f;
            out[length - 1] = (32 * in[length - 1] + 15 * in[length - 2] + 3 * in[length - 3] - 4 * in[length - 4] - 6 * in[length - 5] - 3 * in[length - 6] + 5 * in[length - 7]) / 42f;
        }
        return out;
    }

    /**
     * 5点三次函数平滑
     */
    public static float[] cubicSmooth5(float[] in) {
        int N = in.length;
        float[] out = new float[N];
        if (N < 7) {
            System.arraycopy(in, 0, out, 0, N);
        } else {
            out[0] = (69 * in[0] + 4 * in[1] - 6 * in[2] + 4 * in[3] - in[4]) / 70f;
            out[1] = (2 * in[0] + 27 * in[1] + 12 * in[2] - 8 * in[3] + 2 * in[4]) / 35f;
            for (int i = 2; i <= N - 3; i++) {
                out[i] = (-3 * (in[i - 2] + in[i + 2]) + 12 * (in[i - 1] + in[i + 1]) + 17 * in[i]) / 35f;
            }
            out[N - 2] = (2 * in[N - 5] - 8 * in[N - 4] + 12 * in[N - 3] + 27 * in[N - 2] + 2 * in[N - 1]) / 35f;
            out[N - 1] = (-in[N - 5] + 4 * in[N - 4] - 6 * in[N - 3] + 4 * in[N - 2] + 69 * in[N - 1]) / 70f;
        }
        return out;
    }

    /**
     * 7点三次函数平滑
     */
    public static float[] cubicSmooth7(float[] in) {
        int N = in.length;
        float[] out = new float[N];
        if (N < 7) {
            System.arraycopy(in, 0, out, 0, N);
        } else {
            out[0] = (39 * in[0] + 8 * in[1] - 4 * in[2] - 4 * in[3] + 1 * in[4] + 4 * in[5] - 2 * in[6]) / 42f;
            out[1] = (8 * in[0] + 19 * in[1] + 16 * in[2] + 6 * in[3] - 4 * in[4] - 7 * in[5] + 4 * in[6]) / 42f;
            out[2] = (-4 * in[0] + 16 * in[1] + 19 * in[2] + 12 * in[3] + 2 * in[4] - 4 * in[5] + 1 * in[6]) / 42f;
            for (int i = 3; i <= N - 4; i++) {
                out[i] = (-2 * (in[i - 3] + in[i + 3]) + 3 * (in[i - 2] + in[i + 2]) + 6 * (in[i - 1] + in[i + 1]) + 7 * in[i]) / 21f;
            }
            out[N - 3] = (-4 * in[N - 1] + 16 * in[N - 2] + 19 * in[N - 3] + 12 * in[N - 4] + 2 * in[N - 5] - 4 * in[N - 6] + 1 * in[N - 7]) / 42f;
            out[N - 2] = (8 * in[N - 1] + 19 * in[N - 2] + 16 * in[N - 3] + 6 * in[N - 4] - 4 * in[N - 5] - 7 * in[N - 6] + 4 * in[N - 7]) / 42f;
            out[N - 1] = (39 * in[N - 1] + 8 * in[N - 2] - 4 * in[N - 3] - 4 * in[N - 4] + 1 * in[N - 5] + 4 * in[N - 6] - 2 * in[N - 7]) / 42f;
        }
        return out;
    }
}